package com.angysnail.guava.monitor;

import java.util.List;
import java.util.concurrent.TimeUnit;

import com.angysnail.entity.Person;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Monitor;

public class MonitorTest {

	public static void main(String[] args) throws InterruptedException {
		test1();
	}

	private static void test1() throws InterruptedException {
		for (int i = 0; i < 12; i++) {
			ListAppender appender = new ListAppender(i);
			appender.start();
		}

		TimeUnit.SECONDS.sleep(4);
		// 这样起作用，即代码必须是在monitor之间的才能互相作用
		ListAppender.monitor.enter();
		try {
			ListAppender.list.remove(0);
		} finally {
			ListAppender.monitor.leave();
		}
		// 这个不起作用，不能驱动添加继续
		// ListAppender.monitor.notify();
	}
}

class ListAppender extends Thread {

	ListAppender(int num) {
		setName("thread" + num);
	}

	public static List<Person> list = Lists.newArrayList();
	public static Monitor monitor = new Monitor();
	public static Monitor.Guard guard = new Monitor.Guard(monitor) {

		@Override
		public boolean isSatisfied() {
			return list.size() < 10;
		}
	};

	/**
	 * 1. monitor.enterWhen后，直接就是try
	 * finally，这样可以避免随后的代码有异常而不释放锁。如果是返回值为boolean的，那么需要在if里面使用，请参见monitor的注释
	 * 
	 * 2. 任一时刻，仅有一个线程能进入到monitor的enter和leave中间的代码，
	 * 一定程序可以理解其为加强的synchronized和reenlocker。
	 * 
	 * 3. 不同的api的表现：
	 * 
	 * -> enter()其与synchronized是一样的，只的他的锁是monitor这个对象
	 * 
	 * -> enterIf(Guard guard):boolean 如果满足就进入，不满足就直接返回true/false，不进行等待
	 * 
	 * -> enterWhen(Guard guard):void 如果满足就进入，如果不满足就无限期等待。
	 * 
	 * -> tryEnter():boolean 试图进入，但是不会block，即进就进，进不去就直接走。
	 * 
	 * -> tryEnterIf(Guard guard): boolean 试图进入，不会block，返回true/false
	 * 
	 * @param p
	 * @throws InterruptedException
	 */
	private void addToList(Person p) throws InterruptedException {
		monitor.enterWhen(ListAppender.guard);
		System.out.println(Thread.currentThread().getName() + "|===|");
		try {
			list.add(p);
		} finally {
			monitor.leave();
		}
	}

	private void addToList1(Person p) throws InterruptedException {
		if (monitor.tryEnter()) {// 如果没有获得这个锁就直接 走
			try {
				list.add(p);
			} finally {
				monitor.leave();
			}
		} else {// 如果没有获得就走这一块内容

		}
	}

	@Override
	public void run() {
		Person p = new Person(Thread.currentThread().getName(), 11, false, System.currentTimeMillis());
		try {
			// System.out.println(p);
			this.addToList(p);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
